---
title: Expressions
description: Reference action outputs, webhook payloads, secrets, and more.
icon: dollar-sign
---

import JsonpathNote from '/snippets/jsonpath-note.mdx'

Expressions is how you reference and manipulate data inline in action inputs, run-if conditions, loop expressions, and output schemas.
Tracecat supports the following expression contexts:

| Prefix    | Expression syntax                          | Description                               |
| --------- | ------------------------------------------ | ----------------------------------------- |
| `ACTIONS` | `ACTIONS.<action_slug>.result.<jsonpath>`  | Reference the result of an action         |
| `TRIGGER` | `TRIGGER.<jsonpath>`                       | Reference data passed via webhook or UI   |
| `SECRETS` | `SECRETS.<name>.<key>`                     | Reference a secret                        |
| `FN`      | `FN.<fn_name>(<arg1>, <arg2>, ...)`        | Call an inline function                   |

To use an expression, you must use the `${{ <context>.<expression> }}` syntax:

```yaml
${{ <context>.<expression> }}
```

Expressions are evaluated into values at the start of each action run.

## `ACTIONS` context

<JsonpathNote />

You can reference outputs from a previous action in the same workflow using the `ACTIONS` context.
Actions are referenced by a sluggified version of their name.

<Accordion icon="book-open" title="Example">
  <Steps>
    <Step title="Rename action">
      For example, let's assume you renamed the `core.http_request` action in [Your first workflow](#your-first-workflow) from `HTTP Request` to `Get weather`.
      You can rename the action under the `General` section in the action inputs panel.

      ![Rename action](/img/quickstart/expressions/rename-action.png)
    </Step>
    <Step title="Reference action output">
      You can then reference the `Get weather` action's output in the next action by using the `ACTIONS.get_weather.result` expression.
      For example, you can use the `core.transform.reshape` action as a pass-through action to extract and organize the weather data.

      ```yaml
      value:
        temp: ${{ ACTIONS.get_weather.result.data.current.temperature_2m }}
        rain: ${{ ACTIONS.get_weather.result.data.current.precipitation_probability }}
      ```

      ![Reference action result](/img/quickstart/expressions/reference-action-result.png)

      You can then reference the `temp` and `rain` outputs in downstream actions in the workflow using:

      ```yaml
      ${{ ACTIONS.reshape.result.temp }}
      ${{ ACTIONS.reshape.result.rain }}
      ```
    </Step>
  </Steps>
</Accordion>

## `TRIGGER` context

<Info>
  Check out the [workflow triggers](/tutorials/workflow-triggers.mdx) tutorial for a detailed guide setting up webhooks for workflows.
</Info>

Workflows can be triggered via webhook, manual UI trigger, or the `Execute child workflow` action.
Use the `TRIGGER` context to reference the data from the trigger as a JSON object.


<Accordion title="Manual trigger example" icon="play">
  <Steps>
    <Step title="Send webhook">
      For example, if you send a `POST` request to the workflow's webhook URL with the following payload:

      ```json
      {"lat": 40, "long": 70}
      ```
    </Step>
    <Step title="Reference webhook payload">
      You can reference the `lat` and `long` values in an action's inputs using the `TRIGGER` context.

      ```yaml
      url: https://api.open-meteo.com/v1/forecast
      method: GET
      params:
        latitude: ${{ TRIGGER.lat }}
        longitude: ${{ TRIGGER.long }}
            current: temperature_2m,precipitation_probability
      ```

      ![Reference webhook payload](/img/quickstart/expressions/reference-webhook-payload.png)
    </Step>
  </Steps>
</Accordion>

<Accordion title="Webhook example" icon="globe">
  Given a workflow with a live webhook, the following curl command will send the JSON payload `{"data": {"name": "John", "age": 30}}` and trigger the workflow:

  ```bash
  export WEBHOOK_URL=https://tracecat.com/api/webhooks/<webhook_id>/<secret>
  curl -X POST $WEBHOOK_URL \
      -H "Content-Type: application/json" \
      -d '{"data": {"name": "John", "age": 30}}'
  ```

  The following expression will return the string `John`:

  ```php
  ${{ TRIGGER.data.name }}
  ```
</Accordion>

## `SECRETS` context

Tracecat comes with a built-in secrets manager.
This allows you to store and retrieve sensitive data **scoped to a workspace** without exposing the value in plaintext.
Secrets are encrypted at rest and stored in the database.

Secrets stored in the secrets manager can be accessed using the `SECRETS` prefix:

```php
${{ SECRETS.<name>.<key> }}
```

Tracecat will automatically replace the expression with the secret value at runtime.
Retrieved secrets are deleted from memory after the workflow run completes.

## Operators

You can use standard operators (`+`, `-`, `*`, `/`) on `int`, `float`, `str`, `datetime`, `timedelta`, `list`, and `dict` data in actions.

<Accordion icon="book-open" title="Example">
This expression will return the integer value 3:

```php
${{ 1 + 2 }}
```

And the following expression will return the string `hello world`:

```php
${{ "hello " + "world" }}
```
</Accordion>

## Typecasting

You can convert data from actions from one data type to another (e.g. from string to integer) using the following syntax:

<CodeGroup>
```php Inline
${{ int(<expression>) }}
```

```php Trailing
${{ <expression> -> int }}
```
</CodeGroup>

Supported typecasts:

| Data Type | Behavior |
|-----------|----------|
| int       | Python `int` |
| float     | Python `float` |
| str       | Python `str` |
| bool      | Custom `bool` - true for any truthy value, `1`, or upper/lower case `true` |

<Accordion icon="book-open" title="Example">
`${{ "101" -> int }}` and `${{ int("101") }}` both return the integer object `101`.
</Accordion>

## `FN` context

<Tip>
  Check out the full list of supported functions in the [functions](/cheatsheets/functions) cheatsheet.
</Tip>

Tracecat supports inline functions in the `FN` context.
Here are some examples of functions you can use with `FN`:

<Info>
  For the following function examples, we'll use the `Example alert` JSON as sample data.
  Feel free to copy and paste this into your own workflow to follow along.
</Info>

<Accordion title="Example alert" icon="bell">
```json
{
  "alert": {
    "id": "alert-123456",
    "title": "Suspicious Login Activity",
    "severity": "high",
    "created_at": "2023-11-15T08:45:23Z",
    "source_ip": "203.0.113.42",
    "destination_ip": "10.0.0.15",
    "user": {
      "id": "user-789",
      "email": "john.doe@example.com",
      "department": "Finance"
    },
    "events": [
      {
        "timestamp": "2023-11-15T08:43:12Z",
        "action": "login_attempt",
        "status": "failed",
        "location": "Moscow, Russia",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
      },
      {
        "timestamp": "2023-11-15T08:44:05Z",
        "action": "login_attempt",
        "status": "failed",
        "location": "Moscow, Russia",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
      },
      {
        "timestamp": "2023-11-15T08:45:18Z",
        "action": "login_attempt",
        "status": "success",
        "location": "Moscow, Russia",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
      }
    ],
    "raw_logs": "<syslog><timestamp>2023-11-15T08:45:18Z</timestamp><message>User login successful after multiple failures</message></syslog>",
    "additional_context": {
      "last_successful_login": "2023-11-14T17:22:45Z",
      "usual_location": "New York, USA",
      "risk_score": 85.7
    }
  }
}
```
</Accordion>

```yaml
# --- JSON Processing ---
# Parse a JSON string into an object
result: ${{ FN.deserialize_json(ACTIONS.get_alert.result.raw_data) }}

# Convert an object to a JSON string
result: ${{ FN.serialize_json(ACTIONS.transform_data.result) }}

# Format JSON for readability
result: ${{ FN.prettify_json(ACTIONS.get_alert.result.alert) }}

# Safely access a potentially missing property
result: ${{ FN.lookup(ACTIONS.get_alert.result.alert.user, "department") }}

# Merge multiple objects
result: >-
  ${{ FN.merge([
    ACTIONS.get_user_info.result,
    ACTIONS.get_device_info.result,
    {"alert_id": ACTIONS.get_alert.result.alert.id}
  ]) }}

# --- Date/Time Processing ---
# Convert ISO string to datetime
result: ${{ FN.to_datetime(ACTIONS.get_alert.result.alert.created_at) }}

# Format a datetime
result: ${{ FN.format_datetime(ACTIONS.get_alert.result.alert.created_at, "%Y-%m-%d %H:%M:%S") }}

# Convert datetime to timestamp (seconds since epoch)
result: ${{ FN.to_timestamp(ACTIONS.get_alert.result.alert.created_at) }}

# Calculate time difference in hours
result: >-
  ${{ FN.hours_between(
    ACTIONS.get_alert.result.alert.additional_context.last_successful_login,
    ACTIONS.get_alert.result.alert.created_at
  ) }}

# --- Text Processing ---
# Extract text using regex
result: ${{ FN.regex_extract("<timestamp>(.*?)</timestamp>", ACTIONS.get_alert.result.alert.raw_logs) }}

# Transform text
result: ${{ FN.uppercase(ACTIONS.get_alert.result.alert.title) }}

# --- IP Addresses ---
# Check IP address version
result: ${{ FN.check_ip_version(ACTIONS.get_alert.result.alert.source_ip) }}

# Check if an IP is public
result: ${{ FN.ipv4_is_public(ACTIONS.get_alert.result.alert.source_ip) }}

# Check if an IP is private
result: ${{ FN.ipv4_is_private(ACTIONS.get_alert.result.alert.source_ip) }}
```

Check out the docs on [Data manipulation](/introduction#data-manipulation) to learn more about the different data types and how to manipulate them.
